package com.study.example.gameserver.module.player.manager;

import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.sparrow.cache.entity.AbstractEntity;
import com.sparrow.cache.entity.EntityCache;
import com.sparrow.cache.service.CacheService;
import com.sparrow.common.mergeupdate.impl.DelayMergeBox;
import com.sparrow.common.thread.IoThreadPool;
import com.sparrow.common.util.PlayerHelper;
import com.sparrow.common.uuid.UUIDService;
import com.sparrow.event.annotation.EventReceiver;
import com.study.example.gameserver.base.ConfigService;
import com.study.example.gameserver.event.ServerInitEvent;
import com.study.example.gameserver.module.attr.service.AttrService;
import com.sparrow.common.buff.BuffBox;
import com.study.example.gameserver.module.entity.PlayerData;
import com.study.example.gameserver.module.player.dao.PlayerEntityDao;
import com.study.example.gameserver.module.player.domain.PlayerDataType;
import com.study.example.gameserver.module.player.entity.Player;
import com.study.example.gameserver.module.player.entity.PlayerEntity;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Component
public class PlayerManager {

    private static Logger logger = LoggerFactory.getLogger(PlayerManager.class);

    private Cache<Long, Player> playerCache = CacheBuilder.newBuilder().softValues().build();

    private Map<String, Long> accountToIdMap = new ConcurrentHashMap<>();

    private Map<String, Long> nameToIdMap = new ConcurrentHashMap<>();

    @Autowired
    private IoThreadPool ioExecutorGroup;
    @Autowired
    private CacheService cacheService;
    @Autowired
    private AttrService attrService;
    @Autowired
    private EntityCache<Long, PlayerEntity> playerEntityCache;
    @Autowired
    private ConfigService configService;
    @Autowired
    private PlayerEntityDao playerBaseInfoDao;
    @Autowired
    private UUIDService uuidService;

    @EventReceiver
    public void init(ServerInitEvent event) {
        List<PlayerEntity> list = cacheService.list(PlayerEntity.class);
        for (PlayerEntity playerBaseInfo : list) {
            accountToIdMap.putIfAbsent(PlayerHelper.toAccountKey(playerBaseInfo.getAccount(), playerBaseInfo.getServer()), playerBaseInfo.getPlayerId());
        }

        int server = configService.getServerId();
        long maxId = playerBaseInfoDao.selectMaxId(server);
        uuidService.setServerMaxId(server, maxId);
    }

    public void loadPlayerData(Player player) {
        Long playerId = player.getPlayerId();

        PlayerData[] playerDataArray = new PlayerData[PlayerDataType.values().length];
        for (PlayerDataType type : PlayerDataType.values()) {
            Class<? extends AbstractEntity> dataClass = type.getDataClass();
            EntityCache<Long, ? extends AbstractEntity> cache = cacheService.getEntityCache(dataClass);
            PlayerData data = (PlayerData) cache.loadFromDB(playerId);
            if (data == null) {
                data = (PlayerData) cache.create(playerId, null);
            }
            playerDataArray[type.getOrder() - 1] = data;
            data.afterLoad(player);
            logger.info("player{} 加载{}数据", player.getPlayerId(), type);
        }
        player.setPlayerData(playerDataArray);

        PlayerEntity playerEntity = playerEntityCache.get(playerId);
        player.setEntity(playerEntity);
        player.setMergeUpdateBox(new DelayMergeBox());
        player.setAttrBox(attrService.createPlayerAttrBox(player));
        player.setBuffBox(new BuffBox());
        //计算属性
        attrService.calcAttr(player);
        attrService.calcFightForce(player);
        logger.info("player{} 模块数据加载完毕", player.getPlayerId());
    }

    public Long getPlayerIdByAccountKey(String accountKey) {
        return accountToIdMap.get(accountKey);
    }

    public boolean containName(String name) {
        return nameToIdMap.containsKey(name);
    }


    public void registerPlayerId(String accountKey, Long playerId) {
        accountToIdMap.put(accountKey, playerId);
    }

    public Collection<Long> getPlayerIds() {
        return accountToIdMap.values();
    }

    public Player getPlayer(long playerId) {
        return playerCache.getIfPresent(playerId);
    }

    public Cache<Long, Player> getPlayerCache() {
        return playerCache;
    }
}
